use crate::controller::Error;
use crate::controller::event_handler::candidate_path::EventHandler;
use crate::service::ServiceSet;
use crate::{dto, mq};
use std::sync::Arc;

pub struct CandidatePathController {
    service_set: Arc<ServiceSet>,
    event_handler: EventHandler,
}

impl CandidatePathController {
    pub fn new(service_set: Arc<ServiceSet>, mq_client_set: Arc<mq::client::ClientSet>) -> Self {
        Self {
            service_set: service_set.clone(),
            event_handler: EventHandler::new(service_set, mq_client_set.clone()),
        }
    }

    pub async fn add(
        &self,
        request: &dto::candidate_path::AddRequest,
    ) -> Result<dto::core::candidate_path::AddResponseData, Error> {
        let data = self.service_set.candidate_path_manager.add(request).await?;

        self.event_handler
            .spawn_handle_setup_event(data.candidate_path_id.as_str());

        Ok(data)
    }

    pub async fn list(
        &self,
        request: &dto::candidate_path::ListRequest,
    ) -> Result<dto::candidate_path::ListResponseData, Error> {
        let total_count = self
            .service_set
            .candidate_path_manager
            .count(&request.filter)
            .await?;

        if total_count == 0 {
            return Ok(dto::candidate_path::ListResponseData {
                total_count,
                list: Vec::new(),
            });
        }

        let list = self
            .service_set
            .candidate_path_manager
            .list(&request.filter, request.offset, request.limit)
            .await?;

        Ok(dto::candidate_path::ListResponseData { total_count, list })
    }

    pub async fn list_info(
        &self,
        request: &dto::candidate_path::ListRequest,
    ) -> Result<dto::candidate_path::ListInfoResponseData, Error> {
        let total_count = self
            .service_set
            .candidate_path_manager
            .count(&request.filter)
            .await?;

        if total_count == 0 {
            return Ok(dto::candidate_path::ListInfoResponseData {
                total_count,
                list: Vec::new(),
            });
        }

        let list = self
            .service_set
            .candidate_path_manager
            .list_info(&request.filter, request.offset, request.limit)
            .await?;

        Ok(dto::candidate_path::ListInfoResponseData { total_count, list })
    }

    pub async fn get(
        &self,
        request: &dto::candidate_path::GetRequest,
    ) -> Result<dto::core::candidate_path::CandidatePathItem, Error> {
        let data = self
            .service_set
            .candidate_path_manager
            .get(request.candidate_path_id.as_str())
            .await?;
        Ok(data)
    }

    pub async fn get_info(
        &self,
        request: &dto::candidate_path::GetRequest,
    ) -> Result<dto::candidate_path::CandidatePathInfo, Error> {
        let data = self
            .service_set
            .candidate_path_manager
            .get_info(request.candidate_path_id.as_str())
            .await?;
        Ok(data)
    }

    pub async fn update(&self, request: &dto::candidate_path::UpdateRequest) -> Result<(), Error> {
        if request.params == Default::default() {
            return Ok(());
        }

        self.service_set
            .candidate_path_manager
            .update(request.candidate_path_id.as_str(), &request.params)
            .await?;

        Ok(())
    }

    pub async fn delete(&self, request: &dto::candidate_path::DeleteRequest) -> Result<(), Error> {
        self.service_set
            .candidate_path_manager
            .delete(request.candidate_path_id.as_str())
            .await?;

        self.event_handler.spawn_handle_delete_event(request.candidate_path_id.as_str());
        Ok(())
    }
}
